Imports System.Security.Permissions
Imports CacheMyWork.ProcessesBusinessLogic
Imports CacheMyWork.UserConfiguration

<Assembly: FileIOPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> 
<Assembly: RegistryPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> 
<Assembly: UIPermission(SecurityAction.RequestMinimum, Unrestricted:=True)> 

Public Class uiMainForm
    ' TODO: v2 - When app is toggled to be cached, toggle all document checkboxes by default (i.e. re-open all currently-open docs for "cached apps" by default).

#Region " Variables "

    ''' <summary>
    ''' 
    ''' </summary>
    ''' <remarks>This logging file was originally meant for debugging purposes, before I understood how to use the "DEBUG" and "TRACE" constants.</remarks>
    Private LogFile As System.IO.StreamWriter
    ' TODO: replace _LogFile with a DEBUG or TRACE-based solution

    Dim LogFileName As String

    ''' <summary>
    ''' This variable is set to True when the Save button is clicked, so that the UIForm_FormClosing() routine doesn't throw the confirmation dialog.
    ''' </summary>
    ''' <remarks>
    ''' i.e. the idea is the Confirmation dialog should only be thrown if the user *doesn't* click the Save button, and only if they've left some checkboxes checked.
    ''' Note: this variable needs to be global since it has to be passed between the SaveButton_Click() routine and the UIForm_FormClosing() routine.
    ''' </remarks>
    Dim SaveClicked As Boolean

#End Region

#Region " Event Handlers "

    ''' Shows a Windows Dialog which displays a list of the User's applications as well as the documents held open by those applications.
    Private Sub MainForm_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

        LogFileName = "CacheMyWorkLog.txt"
        LogFile = My.Computer.FileSystem.OpenTextFileWriter(My.Computer.FileSystem.SpecialDirectories.Temp.ToString + "\" + LogFileName, True)

        ' Performance tracing - Log the current date & time at the start of the Tool:
        LogFile.WriteLine("========= Start time = " + Date.Now)

        ' Enable the XP Visual Styles
        Application.EnableVisualStyles()

        ' This method simply gets the initial configuration of the application
        GetAppConfig()

        ' This method generates a list of all interactive processes launched by the user
        BuildCollectionOfUserProcesses()

        ' Set some properties of the checklistbox for its eventual display
        UIApplicationsList.CheckOnClick = True
        UIApplicationsList.Sorted = True

        ' Set the contents of the checklistbox
        PopulateChecklistWithNonHiddenApps()

        ' Performance tracing - Log the current date & time:
        LogFile.WriteLine("========= Finished populating the Form @ " + Date.Now)

    End Sub

    Private Sub AboutToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles AboutToolStripMenuItem.Click

        uiAboutCacheMyWork.ShowDialog()

    End Sub

    Private Sub ContentsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ContentsToolStripMenuItem.Click
        ' Help.ShowHelp(Me, "Help.htm")
        ' TODO: figure out the URL format that loads a local .HTM file.
        ' TODO: v2 - compile the HTM file into a CHM file.

    End Sub

    Private Sub ExitToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ExitToolStripMenuItem.Click

        Me.Close()

    End Sub

    Private Sub HideApplicationsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles HideApplicationsToolStripMenuItem.Click
        Dim HideApplicationsForm As Form
        HideApplicationsForm = New uiHideApplications()

        HideApplicationsForm.ShowDialog()
    End Sub

    Private Sub OptionsToolStripMenuItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OptionsToolStripMenuItem.Click
        ' open up the Options configuration form when the Tools, Options menu is selected
        Dim OptionsForm As Form
        OptionsForm = New uiOptions()

        OptionsForm.ShowDialog()
    End Sub

    Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles uiSaveButton.Click
        ' Once the user clicks this button, write the selected apps (& documents) into the user's RunOnce Registry key to launch the apps at next Logon.

        ' Performance tracing - Log the current date & time:
        LogFile.WriteLine("========= Start populating Registry with chosen Apps @ " + Date.Now)

        SaveClickedOrUserConfirmed()

        ' Set state to show the Save button has been clicked
        SaveClicked = True

        ' Now close the MainForm
        Me.Close()

    End Sub

    Private Sub UIForm_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

        ' TODO: combine the SaveButton.Click event in this handler, so we can eliminate the looping code that returns to this Sub and has to be specially handled.

        ' If the user has checked any checkboxes, but they didn't previously click the Save button, then we should confirm that they do NOT want to cache those selected items
        ' If the user hasn't checked any checkboxes, and they haven't clicked Save, then they're just trying to close the app, so just continue with the Closing event
        If UIApplicationsList.CheckedItems.Count > 0 AndAlso SaveClicked = False Then

            Dim _responseValue As DialogResult
            _responseValue = MessageBox.Show("You selected some items but they won't be cached - do you want to cache these applications so they automatically run at your next logon?", "Uncached Items", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button3, 0, False)

            Select Case _responseValue
                ' If YES, then loop back and save the selected items as if they'd chosen the Save button
                Case Windows.Forms.DialogResult.Yes
                    SaveClickedOrUserConfirmed()
                    ' If NO, keep processing the FormClosing event
                Case Windows.Forms.DialogResult.No
                    Exit Select
                    ' If CANCEL, try to return to the main Form with the checklist that wasn't dealt with.
                Case Windows.Forms.DialogResult.Cancel
                    ' Setting "e.Cancel = True" should cause the FormClosing() event to halt, and to return to the application.
                    e.Cancel = True
            End Select

        End If

    End Sub

    ''Private Sub UIApplicationsList_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles UIApplicationsList.MouseClick
    ''    ' When user clicks an item in the CheckedListBox, the app will display a ToolTip
    ''    ' TODO: find a use for the Tooltip - could it show the entire Command Line for the process?  Indicate whether the process is elevated?

    ''    Dim _Point As New Point(e.X, e.Y)
    ''    Dim _Index As Integer
    ''    Dim _CommandLine As String = String.Empty
    ''    Dim _ProcessName As String = String.Empty
    ''    Dim _ProcessFileDescription As String = String.Empty

    ''    Try
    ''        ' Get the index value corresponding to where the user clicked:
    ''        _Index = Me.UIApplicationsList.IndexFromPoint(_Point.X, _Point.Y)

    ''        ' Get the text string corresponding to that index position in the CheckedListBox
    ''        _ProcessFileDescription = Me.UIApplicationsList.GetItemText(Me.UIApplicationsList.Items(_Index))

    ''        ' Transform back from Process.MainModule.FileVersionInfo.FileDescription to Process.ProcessName
    ''        ' TODO: either figure out how to get back to a ProcessName, or change the Key for the ProcessesToShowUser to the FileDescription property


    ''        ' Next, lookup the Command Line for that process and set the Tooltip value to that String:
    ''        ' Note: I'm nesting the lookup of the Process object by the "name" index inside the GetProcessDescriptiveName method.  This indirect method may need to be shortened.
    ''        UIAppsToolTip.SetToolTip(Me.UIApplicationsList, GetProcessPropertyFromWMI(ProcessesToShowUser.Item(_ProcessName), "CommandLine"))

    ''    Catch ex As ArgumentOutOfRangeException
    ''        UIAppsToolTip.SetToolTip(Me.UIApplicationsList, String.Empty)

    ''    End Try

    ''End Sub

#End Region

#Region " Private Methods "

    ''' <summary>
    ''' Enumerates the user's selections from the main UI to determine which processes to cache.
    ''' </summary>
    ''' <param name="selectedItems">
    ''' Collection of the items as ProcessDescriptiveName that were selected by the user.</param>
    ''' <remarks></remarks>
    Private Sub SetUserSelections(ByVal selectedItems As Collection)
        'Friend Shared Sub SetUserSelections(ByVal selectedItems As Collection)

        ' First convert each selected item in the UIForm's CheckedListBox into a Process object:
        ' Retrieve the Process from EnumeratedProcesses collection whose index Key = CheckedItem.ToString, and enter its Command Line as a new entry in the RunOnce key
        For Each _item As String In selectedItems

            ' TODO: remove this variable and its usage, as well as the ProcessLookupTable, once I've confirmed the routine is retrieving the Process & Command Line correctly from the Structure embedded in ProcessesToShowUser
            Dim _CheckedProcess As String = String.Empty
            Dim _Process As EnumeratedProcess

            _CheckedProcess = ProcessLookupTable(_item) ' Lookup ProcessName, given the ProcessDescriptiveName
            _Process = EnumeratedProcesses(_CheckedProcess) ' Lookup Process object, given the ProcessName

            ' Then write each app to the HKCU RunOnce registry key as a separate entry, using the app's current command line
            'My.Computer.Registry.SetValue(HKCURUNONCE, _CheckedItem, _RegistryValue)
            My.Computer.Registry.SetValue(HKCURUNONCE, _Process.ProcessName, _Process.ProcessCommandLine)

            ' TODO: pass these logging entries back to the calling code
            'LogFile.WriteLine("The process " + _Process.ProcessName + " has been added to the user's RunOnce Registry key with the command line = " + _Process.ProcessCommandLine)
        Next _item

        ' TODO: pass these logging entries back to the calling code
        'LogFile.WriteLine("========= Finished populating Registry @ " + Date.Now)

    End Sub

    ''' <summary>
    ''' Populate the main UI's checklistbox with the list of non-hidden, user-visible processes from which the user may select any or all to cache.
    ''' </summary>
    ''' <remarks>
    ''' This method is called as the last step upon application startup, and is also called after the user makes changes using Tools, Hide Applications.
    ''' </remarks>
    Friend Sub PopulateChecklistWithNonHiddenApps()
        ' TODO: Append the unique "Key" string (from each entry in the UserAppsToDisplay collection) in addition to the non-unique "process.ProcessName" string, to provide unique listings (and indexes).
        For Each _Process As EnumeratedProcess In EnumeratedProcesses.Values

            Try
                ' Only add those processes that haven't been hidden by the user, nor removed from the UI by the code
                If (_Process.ProcessWillBeDisplayedToUser) Then
                    ' RESEARCH: is there a way to extract the Key value from the Collection, given the position in the Collection or the indexed item's name?
                    UIApplicationsList.Items.Add(_Process.ProcessDescriptiveName)

                End If

            Catch ex As System.ApplicationException
                ' The only known case where this Exception occurs is when the process exits after it's added to the ProcessesToShowUser array
                ' Since we're tracking this state in the EnumeratedProcesses class, we shall toggle the .Exists property to "False"
                _Process.Exists = False

            End Try

        Next _Process

        ' Show the count of Processes in the Status Bar
        Status.Text = UIApplicationsList.Items.Count.ToString + " Applications"
    End Sub

    ''' <summary>
    ''' Initiates the process of saving the cached applications to be launched later.
    ''' </summary>
    ''' <remarks>
    ''' Called either when the user has clicked the Save button in the UI or when the user confirms they'd like to cache the selected entries (when the "you have unsaved entries" warning is made available).
    ''' </remarks>
    Private Sub SaveClickedOrUserConfirmed()

        Dim _checkedItems As Collection
        _checkedItems = New Collection()

        For Each _item As String In UIApplicationsList.CheckedItems
            _checkedItems.Add(_item.ToString)
        Next

        SetUserSelections(_checkedItems)

    End Sub

#End Region

End Class
